var OurGame = {
    FPSlimit:30,
    curFPS:0,
    numFramesDrawn:0,
    totalFramesDrawn:0,
    fpsInterval:setInterval(updateFPS, 1000),
    numResourcesLoaded:0,
    totalResources:14,
    gameModeSelected:false,
    canvas:null,
    ctx:null,
    images:{},
    sounds:{},
    grid:32,
    maxGrid:48,
    backGrid:128,
    maxBackGrid:192,
    offSet:8,
    backOffset:32,
    mapLoaded:false,
    contentLoaded:false,
    players:[],
    myPlayerIndex: null,
    deadPlayers:[],
    bombs:[],
    buttons:null,
    keys:[],
    mapFiles:[],
    keyLock:[],
    booleanMap:[],
    isGameOver:false,
    settings:null,
    appKey:'8d367b23c1b1356383d5', // pusher appkey
    UID:null,
    playerUIDs: [], // this contains myself in first place, and players who are not selected by initiator are null
    localStorageVersion: '1'
};

level = {
    name:"Error 100 - Level not found",
    map:[],
    spawnPos:{
        "x":0,
        "y":0
    }
};

OurGame.settings = new Settings();

window.addEventListener('keydown', keyDown, true);
window.addEventListener('keyup', keyUp, true);
window.addEventListener('blur', canvasLostFocus, true);

window.onbeforeunload = function () {
    if (OurGame.UID){
        markUserOffline();
    }
};

try {
    document.onload = init();
} catch(e) {
    stickyError(
        "An unknown error occurred!",
        e
    );
}

function localHostGameInitWithGameID() {
    log("Localhost!");
    OurGame.UID = getURLParameter("UID");
    if (OurGame.UID) {
        log("Registering");
        pusher = new Pusher(OurGame.appKey);
        pusher.connection.bind('connected', function () {
            log("CONNECTED!");
            OurGame.socketID = pusher.connection.socket_id;
            createOrMarkOnline(function () {
                log("createOrMarkOnline DONE");
                checkJoinPermission(OurGame.gameID);
            });
        });
    } else {
        error('NO UID URL PARAMTETER, WHEN LOCALHOST');
    }
}
function liveGameInitWithGameID() {
    log("Production");
    doLogin(function () {
        if (OurGame.UID) {
            log("Registering");
            createOrMarkOnline(function () {
                log("createOrMarkOnline DONE");
                checkJoinPermission(OurGame.gameID);
            });
        } else {
            stickyError(
                'Automatic login failed! \n ' +
                    'Please log in manually and refresh this page \n' +
                    'Allow all popup windows from this page',
                'Automatic login failed!'
            );
        }
    });
}
function gameJoinWithGameID() {
    OurGame.isMultiplayer = true;
    showInfoScreenInLobby('Please wait');
    if (conf.isLocalHost) {
        localHostGameInitWithGameID();
    } else {
        liveGameInitWithGameID();
    }
    OurGame.canvas = document.getElementById('canvas');
    OurGame.ctx = OurGame.canvas.getContext("2d");
    loadContext();
    OurGame.interValID = setInterval(gameLoop, 1000 / OurGame.FPSlimit);
}
function init() {
    createLobby();
    OurGame.gameID = getURLParameter("gameID");
    if (OurGame.gameID) {
        gameJoinWithGameID();
    } else {
        OurGame.canvas = document.getElementById('canvas');
        OurGame.ctx = OurGame.canvas.getContext("2d");
        loadContext();
        setInterval(gameLoop, 1000 / OurGame.FPSlimit);
    }
}

function initTwoPlayerGame() {
    OurGame.gameModeSelected = true;
    jQuery('#lobby').css("visibility", "hidden");

    var p1 = new Player(uniqueID());
    p1.setPos(level.spawnPos.x[0], level.spawnPos.y[0]);
    p1.assignKeys(KeyBoardType.WASD);
    OurGame.players.push(p1);
    createProfileSideBar(p1, 0);

    var p2 = new Player(uniqueID());
    p1.setPos(level.spawnPos.x[1], level.spawnPos.y[1]);
    p2.assignKeys(KeyBoardType.ARROWS);
    OurGame.players.push(p2);
    createProfileSideBar(p2, 1);

    for (var i = 0; i < OurGame.players.length; i++) {
        level.map[Math.floor(OurGame.players[i].x / OurGame.grid)][Math.floor(OurGame.players[i].y / OurGame.grid)] = "p" + i;
    }
    addGeneratedUpgrades(generateUpgrades());
}

function createMultiplayersAndStart(playerUIDs) {
    for (var i = 0; i < playerUIDs.length; i++) {
        var p = null;
        if (OurGame.UID == playerUIDs[i]){
            p = new Player(playerUIDs[i]);
            createProfileSideBar(p, i);
            p.assignKeys(KeyBoardType.ARROWS);
            OurGame.myPlayerIndex = i;
        } else{
            p = new MultiPlayer(playerUIDs[i]);
            createMultiOtherPlayersSideBar(p, i);
        }
        OurGame.players[OurGame.players.length] = p;
        p.setPos(level.spawnPos.x[i], level.spawnPos.y[i]);
        level.map[Math.floor(p.x / OurGame.grid)][Math.floor(p.y / OurGame.grid)] = "p" + i;
        log("Created Player with id: " + playerUIDs[i]);
    }
    gameModeSelectionEndActivities();
}

function initMultiplayerGame() {
    if (OurGame.UID) {
        log("Multi: " + OurGame.UID);
        OurGame.isMultiplayer = true;
        var currentDateTime = new Date();
        currentDateTime.setMinutes(currentDateTime.getMinutes()+1);
        var currentDateTimeString = currentDateTime.format("yyyy-mm-dd HH:MM:ss");
        log('Current datetime: ' + currentDateTimeString);
        OurGame.isInitator = true;
        OurGame.maxNrOfPlayers = OurGame.playerUIDs.length;
        OurGame.curNrOfPlayers = 1;
        var data = {
            "gameID":OurGame.gameID,
            "nrOfPlayers":OurGame.maxNrOfPlayers,
            "initatorID":OurGame.UID,
            "itendedPlayers":removeNULLfromarray(OurGame.playerUIDs),
            "startTime":currentDateTimeString
        };
        var success = function (data) {
            if (data.status == "FAILURE") {
                stickyError('An error occurred when creating a new game! \n Please try again!', 'ERROR: ' + data.reason);
            } else {
                startGameWaitScreen([OurGame.UID],removeNULLfromarray(OurGame.playerUIDs), OurGame.maxNrOfPlayers);
                initChannel();
            }
        };
        sendData("/initGame", JSON.stringify(data), success);
    } else {
        stickyError(
            'There was a problem logging you in! Please enable popup windows and refresh this page!',
            'You still do not have UID'
        );
    }
}

function loadContext() {
    head.js("js/maps/map_001.js", mapLoaded);
    loadImage("spritesheet1");
    loadImage("backsheet1");
    loadImage("masks1");
    loadImage("characters/c1");
    loadImage("characters/c2");
    loadImage("characters/c3");
    loadImage("characters/c4");
    loadImage("characters/c5");
    loadImage("characters/c6");
    loadImage("characters/c7");
    loadImage("characters/c8");
    loadImage("characters/c9");
    loadSound("Balloon-Popping");
    loadSound("Ready-To-Burst");
}

function canvasLostFocus(evt) {
    OurGame.keys = new Array();
}

function updateFPS() {
    OurGame.curFPS = OurGame.numFramesDrawn;
    OurGame.numFramesDrawn = 0;
}

function gameModeStarted() {
    if (OurGame.isGameOver) {
        clear();
        draw();
        drawGameOver();
        drawButtons();
    } else {
        update();
        clear();
        draw();
    }
}

function gameLoaded() {
    if (OurGame.gameModeSelected) {
        gameModeStarted();
    } else {
        draw();
        updateGameSelecionKeys();
    }
}

function gameLoop() {
    if (OurGame.contentLoaded && OurGame.mapLoaded) {
        gameLoaded();
    } else {
        drawLoading();
    }
}

function gameOverActivities() {
    OurGame.isGameOver = true;
    if (OurGame.isMultiplayer && OurGame.isInitator){
        gameOver();
    }
    if (!OurGame.buttons) {
        OurGame.buttons = [];
    }
    OurGame.canvas.addEventListener('mousedown', mouseDownOnButtons, false);
    OurGame.canvas.addEventListener('mousemove', mouseMoveOnButtons, false);
    OurGame.buttons.push(new StartNewGame({x:220, y:400, w:180, h:50, text:"New Game"}));
}

function updateBombs() {
    for (var i = 0; i < OurGame.bombs.length; i++) {
        if (OurGame.bombs[i] !== undefined) {
            OurGame.bombs[i].update();
            if (OurGame.bombs[i] !== undefined) {
                var iX = Math.floor(OurGame.bombs[i].x / OurGame.grid);
                var iY = Math.floor(OurGame.bombs[i].y / OurGame.grid);

                var matrixElement = level.map[iX][iY];
                if (matrixElement.charAt(0) !== "f") {
                    if (isNotAlreadyInElement(matrixElement, i.toString(), "b")) {
                        level.map[iX][iY] += ("/b" + i);
                    }
                } else {
                    level.map[iX][iY] = "b" + i;
                }
            }
        }
    }
}

function updatePlayers(i) {
    if (OurGame.players[i]) {
        updateArrowKeys(OurGame.players[i]);

        if (OurGame.players[i].update(i.toString())) {
            var iX = Math.floor(OurGame.players[i].x / OurGame.grid);
            var iY = Math.floor(OurGame.players[i].y / OurGame.grid);
            var matrixElement = level.map[iX][iY];
            matrixElement = checkForAndAddUpgrade(matrixElement, i, iX, iY);
            if (matrixElement.charAt(0) !== "f") {
                if (isNotAlreadyInElement(matrixElement, i.toString(), "p")) {
                    level.map[iX][iY] += ("/p" + i);
                }
            } else {
                level.map[iX][iY] = "p" + i;
            }
        }
    }
}

function update() {
    for (var i = 0; i < OurGame.players.length; i++) {
        if (OurGame.players[i]){
            if (OurGame.players[i].isAlive()) {
                updatePlayers(i);
            } else {
                removeMatrixObject(OurGame.players[i].x, OurGame.players[i].y, OurGame.players[i].id, "p", "lopp");
                OurGame.deadPlayers.push(OurGame.players[i]);
                OurGame.players[i] = undefined;
                if (nrOfRemainingPlayers() === 1) {
                    gameOverActivities();
                }
            }
        }
    }
    updateBombs();
}

function nrOfRemainingPlayers() {
    var nr = 0;
    for (var i = 0; i < OurGame.players.length; i++) {
        if (OurGame.players[i]) {
            nr = nr + 1;
        }
    }
    return nr;
}

function drawButtons() {
    if (OurGame.buttons) {
        for (var k = 0; k < OurGame.buttons.length; k++) {
            OurGame.buttons[k].draw();
        }
    }
}

function draw() {
    drawBackground();
    drawWorld();
    drawBombExlposions();
    if (OurGame.settings.isHighDetail()) {
        drawClouds();
    }
    drawMasks();
    drawHud();
}

function drawBombExlposions() {
    for (var i = 0; i < OurGame.bombs.length; i++) {
        if (OurGame.bombs[i]) {
            OurGame.bombs[i].drawExplosionExt();
        }
    }
}

function drawMasks() {
    OurGame.ctx.drawImage(OurGame.images["masks1"], 0, 25, 20, 280, 0, 0, 20, 512);  //left
    OurGame.ctx.drawImage(OurGame.images["masks1"], 65, 0, 280, 20, 0, 0, 608, 20); //top
    OurGame.ctx.drawImage(OurGame.images["masks1"], 20, 25, 20, 280, 588, 0, 20, 512); //right
    OurGame.ctx.drawImage(OurGame.images["masks1"], 65, 20, 280, 20, 0, 492, 608, 20); //bottom
}

function drawBackground() {
    var backgroundHorizontalSize = 5;
    var backgroundVerticalSize = 4;
    for (var i = 0; i < backgroundHorizontalSize; i++) {
        for (var j = 0; j < backgroundVerticalSize; j++) {
            if (i % 2 == 0) {
                OurGame.ctx.drawImage(OurGame.images["backsheet1"], 0, 0, OurGame.maxBackGrid, OurGame.maxBackGrid, (i * OurGame.backGrid) - OurGame.backOffset, (j * OurGame.backGrid) - OurGame.backOffset, OurGame.maxBackGrid, OurGame.maxBackGrid);
            } else {
                OurGame.ctx.drawImage(OurGame.images["backsheet1"], OurGame.maxBackGrid, 0, OurGame.maxBackGrid, OurGame.maxBackGrid, (i * OurGame.backGrid) - OurGame.backOffset, (j * OurGame.backGrid) - OurGame.backOffset, OurGame.maxBackGrid, OurGame.maxBackGrid);
            }
        }
    }
}

function checkIfAnyMoreObjectsTodraw(matrixObjects) {
    for (var k = 1; k < matrixObjects.length; k++) {
        switch (matrixObjects[k].charAt(0)) {
            case "b":
                var index = parseInt(matrixObjects[k].charAt(1));
                if (OurGame.bombs[index]) {
                    OurGame.bombs[index].draw();
                }
                break;
            case "p":
                var index = parseInt(matrixObjects[k].charAt(1));
                if (OurGame.players[index]) {
                    if (OurGame.players[index].isAlive()) {
                        OurGame.players[index].draw();
                    }
                }
                break;
        }
    }
}

function drawWorld() {
    var mapHorizontalSize = level.map.length;
    var mapVerticalSize = level.map[0].length;

    for (var j = 0; j < mapVerticalSize; j++) {
        for (var i = 0; i < mapHorizontalSize; i++) {
            var matrixElement = level.map[i][j];
            var matrixObjects = matrixElement.split("/");
            var tnum = parseInt(matrixObjects[0].charAt(1));

            switch (matrixObjects[0].charAt(0)) {
                case 'w':
                    drawGridObject(OurGame.images["spritesheet1"], tnum, 1, (i * OurGame.grid) - OurGame.offSet, (j * OurGame.grid) - OurGame.offSet);
                    break;
                case 'h':
                    drawGridObject(OurGame.images["spritesheet1"], tnum + 4, 1, (i * OurGame.grid) - OurGame.offSet, (j * OurGame.grid) - OurGame.offSet);
                    break;
                case 'e':
                    drawGridObject(OurGame.images["spritesheet1"], tnum, 0, (i * OurGame.grid) - OurGame.offSet, (j * OurGame.grid) - OurGame.offSet);
                    break;
                case 'u':
                    drawGridObject(OurGame.images["spritesheet1"], tnum - 1, 5, (i * OurGame.grid) - OurGame.offSet, (j * OurGame.grid) - OurGame.offSet);
                    checkIfAnyMoreObjectsTodraw(matrixObjects);
                    break;
                case 'p':
                    checkIfAnyMoreObjectsTodraw(matrixObjects);
                    if (OurGame.players[tnum]) {
                        if (OurGame.players[tnum].isAlive()) {
                            OurGame.players[tnum].draw();
                        }
                    }
                    break;
                case 'b':
                    checkIfAnyMoreObjectsTodraw(matrixObjects);
                    if (OurGame.bombs[tnum]) {
                        OurGame.bombs[tnum].draw();
                    }
                    break;
            }
        }
    }
}

function drawClouds() {
    var dist = 700;
    for (var i = 0; i <= 2; i++) {
        OurGame.ctx.drawImage(OurGame.images["masks1"],
            45, 45, 55, 55,
            (OurGame.totalFramesDrawn + (dist / 2) * i) % (OurGame.canvas.width + dist + 55) - dist,
            (OurGame.totalFramesDrawn + (dist / 2) * i) % (OurGame.canvas.height + dist + 55) - dist,
            dist + 55, dist + 55);
        OurGame.ctx.drawImage(OurGame.images["masks1"],
            45, 45, 55, 55,
            (OurGame.totalFramesDrawn + (dist / 2) * i) % (OurGame.canvas.width + dist + 55) - dist,
            (OurGame.totalFramesDrawn + (dist / 2) * i + dist) % (OurGame.canvas.height + dist + 55) - dist,
            dist + 55, dist + 55);
    }
}

function drawHud() {
    OurGame.ctx.save();
    OurGame.ctx.setTransform(1, 0, 0, 1, 0, 0);

    //FPS
    OurGame.ctx.fillStyle = "#000";
    OurGame.ctx.font = "bold 12px sans-serif";
    OurGame.ctx.fillText("fps: " + OurGame.curFPS + "/" + OurGame.FPSlimit, 10, 20);
    ++OurGame.numFramesDrawn;
    ++OurGame.totalFramesDrawn;

    OurGame.ctx.restore();
}

function drawGameOver() {
    OurGame.ctx.save();

    OurGame.ctx.fillStyle = "#000";
    OurGame.ctx.globalAlpha = 0.6;
    OurGame.ctx.fillRect(0, 0, OurGame.canvas.width, OurGame.canvas.height);

    OurGame.ctx.fillStyle = "#FFF";
    OurGame.ctx.globalAlpha = 1;
    OurGame.ctx.font = 'bold 30px sans-serif';
    OurGame.ctx.lineWidth = 1;
    OurGame.ctx.fillText('Game Over!', OurGame.canvas.width / 2 - 80, OurGame.canvas.height / 2 - 20);
    OurGame.ctx.restore();
}

function drawLoading() {
    OurGame.ctx.save();
    OurGame.ctx.setTransform(1, 0, 0, 1, 0, 0);

    OurGame.ctx.clearRect(0, 0, OurGame.canvas.width, OurGame.canvas.height);

    OurGame.ctx.fillStyle = "#FFF";

    OurGame.ctx.font = 'bold 30px sans-serif';
    OurGame.ctx.lineWidth = 1;
    OurGame.ctx.strokeStyle = "#000";
    var dots = "";
    for (var i = 1; i < (OurGame.numFramesDrawn / 15 % 30); i++) {
        dots += ".";
        if (i > 2) {
            break;
        }
    }
    OurGame.numResourcesLoaded = 0;
    OurGame.totalResources = 1;
    OurGame.ctx.fillText('Loading' + dots, OurGame.canvas.width / 2 - 50, OurGame.canvas.height / 2 - 20);
    OurGame.ctx.strokeText('Loading' + dots, OurGame.canvas.width / 2 - 50, OurGame.canvas.height / 2 - 20);
    OurGame.ctx.fillText(OurGame.numResourcesLoaded + "/" + OurGame.totalResources, OurGame.canvas.width / 2 - 15, OurGame.canvas.height / 2 + 10);
    OurGame.ctx.strokeText(OurGame.numResourcesLoaded + "/" + OurGame.totalResources, OurGame.canvas.width / 2 - 15, OurGame.canvas.height / 2 + 10);
    ++OurGame.numFramesDrawn;

    OurGame.ctx.restore();
}

function clear() {
    // Store the current transformation matrix
    OurGame.ctx.save();
    // Use the identity matrix while clearing the canvas
    OurGame.ctx.setTransform(1, 0, 0, 1, 0, 0);
    OurGame.ctx.clearRect(0, 0, OurGame.canvas.width, OurGame.canvas.height);
    // Restore the transform
    OurGame.ctx.restore();
}

function removePlayerFromPosition(i) {
    var newPlayers = [];
    for (var j = 0; j < OurGame.players.length; j++) {
        if (OurGame.players[j]) {
            if (i !== j) {
                new Players.push(OurGame.players[j]);
            } else {
                OurGame.deadPlayers.push(OurGame.players[j]);
            }
        }
    }
    return newPlayers;
}